/*  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License , or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING.  If not, write to
      The Free Software Foundation, Inc.
      59 Temple Place, Suite 330
      Boston, MA 02111 USA

    You may contact the author by:
       e-mail:  triphop@triphop.org

*************************************************************************/

#include "Qx3Model.hh"
#include <iostream>
#include <fstream>
#include <strstream>
#include <linux/videodev.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>


using namespace std;

/*
 * Implement the QX3 Model class
 */
Qx3Model* Qx3Model::instance = 0;

Qx3Model::~Qx3Model() {
	if( instance != 0 ) {
                instance->setBottomLight(false);
                instance->setTopLight(false);
		delete instance;
	}
}

Qx3Model* Qx3Model::getInstance(void) {
	if( instance == 0 ) { 
		instance = new Qx3Model();
	}

	return instance;
}


const char* Qx3Model::getFrame(void) {
	static char buffer[352*288*4];

	int buflen = sizeof(buffer);
	int len = 0;

//# Capture a frame from the camera
        ioctl(device, VIDIOCMCAPTURE, &v_map);
//# Wait for end of frame
        ioctl(device, VIDIOCSYNC, &v_map);

        return (char *)map;
}

void Qx3Model::on_monitortimer_timeout()
{

    bool newbuttonstate = settings.getBoolSetting("button");
    if(newbuttonstate) {
        emit buttonPressed();
        getFrame();
    }

    bool newcradlestate = settings.getBoolSetting("cradled");

    if(newcradlestate != cradlestate){
        emit cradleChanged(newcradlestate);
        cradlestate = newcradlestate;

        if(!cradlestate && this->getBottomLight())
        {
            setBottomLight(false);
            setTopLight(true);
        }
    }

}

void Qx3Model::run()
{
    monitor_timer = new QTimer();

    connect( monitor_timer, SIGNAL(timeout()), Qx3Model::getInstance(), SLOT(on_monitortimer_timeout()) );

    monitor_timer->start(1000);

    exec();
}

int Qx3Model::setupVideo(string devfile, string cpiafile) {
#ifdef DEBUG
	cout << "Video device: " << devfile << endl;
	cout << "Cpia proc: " << cpiafile << endl;
#endif
        QDir cpiadir("/proc/cpia");

        if(cpiadir.exists() && cpiadir.entryList().count() > 2)
        {
            cpiadir.setFilter(QDir::Files);
            QStringList filelist = cpiadir.entryList();

            cpia_file = QString("/proc/cpia/%1").arg(filelist.at(0));
            dev_file = QString("/dev/%1").arg(filelist.at(0));

            cerr << "using device: " << cpia_file.toStdString() << endl;
            if(!QFile::exists(dev_file)) return -1;

            if( !device < 0 ) {
                    cerr << "Video is alreasy configured" << endl;
                    return -1;
            }

//            dev_file = devfile;
//            cpia_file = cpiafile;

            settings.setFilename(cpia_file);

            device = open(dev_file.toAscii(), O_RDWR);
            if(device < 0) {
                    cerr << "could not open the video device"<<endl;

                    return device;
            }

            ioctl (device, VIDIOCGCAP, &vid_caps);
            ioctl (device, VIDIOCGWIN, &vid_win);
            ioctl (device, VIDIOCGPICT, &vid_pic);

            vid_pic.palette = VIDEO_PALETTE_RGB32;
            vid_pic.depth = 32;
            vid_pic.brightness = vid_pic.colour = vid_pic.contrast = vid_pic.hue = vid_pic.whiteness = 32767;
            if(ioctl (device, VIDIOCSPICT, &vid_pic) == -1) {
                if(errno == EBADF) cerr << "EBADF" << endl;
                if(errno == EINVAL) cerr << "EINVAL" << endl;
              cerr << "wrong palette/depth" << endl;
    //                close(device);
     //               return -1;
            }

            vid_win.x=0;
            vid_win.y=0;
            vid_win.width=352;
            vid_win.height=288;
            if (ioctl (device, VIDIOCSWIN, &vid_win) == -1) {
                    cerr << "ioctl (VIDIOCSWIN)" << endl;
                    return -1;
            }


            struct video_mbuf m_buf;
            ioctl(device, VIDIOCGMBUF, &m_buf); /* For simple image grabbing, do not consider the frames and offsets field of m_buf */
    //Map video capture card memory to user space memory
            map = mmap(0, m_buf.size, PROT_READ, MAP_SHARED, device, 0); /* PROT_READ specifies that the memory mapped will only be read from.
                                                                          * MAP_SHARED specifies that a change to the video memory will change
                                                                          * the user space memory
                                                                          * A good description of mmap() is available at http://www.opengroup.org/onlinepubs/7908799/xsh/mmap.html */
    //Set the capture parameters for the mapped area
            v_map.frame = 0;
            v_map.width = 352;
            v_map.height = 288;
            v_map.format = VIDEO_PALETTE_RGB24;

            start();
            return 1;

        }
        else{
            return -1;
        }
}

//bool Qx3Model::getLineBoolean( string token ) {
//        std::ifstream from(cpia_file);
//	char line[256];
//	bool found = false;
//	while( !from.eof()) {
//		from.getline(line, 256);
//		string strline(line);
//		if(strline.find(token, 0) != string::npos) {
//			std::istrstream parsline( line );
//			string top,val;
//			parsline >> top >> val;
//
//			if( val == "on" ) {
//				found = true;
//			}
//		}
//	}
//	from.close();
//	return found;
//}

bool Qx3Model::getTopLight(void) {
        return settings.getBoolSetting("toplight"); //getLineBoolean("toplight:");
}

void Qx3Model::setTopLight(bool state) {

        if(this->getBottomLight()) this->setBottomLight(false);

        settings.setBoolOnOffSetting("toplight", state);
//        std::ofstream to(cpia_file.c_str());
//	to << "toplight: " << (state ? "on":"off") << endl;
//	to.close();
        this->getFrame();
}

bool Qx3Model::getBottomLight(void) {
        return settings.getBoolSetting("bottomlight"); //getLineBoolean("bottomlight:");
}

void Qx3Model::setBottomLight(bool state) {
    if(this->getTopLight()) this->setTopLight(false);

    settings.setBoolOnOffSetting("bottomlight", state);
    this->getFrame();
//    std::ofstream to(cpia_file.c_str());
//	to << "bottomlight: " << (state?"on":"off") << endl;
//	to.close();
}

uint Qx3Model::getContrast(void) {

   return settings.getIntSetting("contrast");
//  ioctl (device, VIDIOCGPICT, &vid_pic);
//        return vid_pic.contrast;
}

uint Qx3Model::getBrightness(void) {
  return settings.getIntSetting("brightness");
//  ioctl (device, VIDIOCGPICT, &vid_pic);
//        return vid_pic.brightness;
}

uint Qx3Model::getColor(void) {
    return settings.getIntSetting("saturation");
// ioctl (device, VIDIOCGPICT, &vid_pic);
//        return  vid_pic.colour;
}
	
void Qx3Model::setContrast(uint contrast) {

        settings.setIntSetting("contrast", contrast);
//        vid_pic.contrast = contrast;
//
//        if (ioctl (device, VIDIOCSPICT, &vid_pic) == -1) {
//                cerr << "ioctl (VIDIOCSPICT)";
//                std::ofstream to(cpia_file.c_str());
//                to << "contrast: " << contrast << endl;
//                to.close();
//        }
}

void Qx3Model::setBrightness(uint brightness) {

        settings.setIntSetting("brightness", brightness);
//        vid_pic.brightness = brightness;
//
//        if (ioctl (device, VIDIOCSPICT, &vid_pic) == -1) {
//                cerr << "ioctl (VIDIOCSPICT)";
//                std::ofstream to(cpia_file.c_str());
//                to << "brightness: " << brightness << endl;
//                to.close();
//        }


}

void Qx3Model::setBlueGain(int blueGain)
{
    settings.setIntSetting("blue_gain", blueGain);
}

int Qx3Model::getBlueGain()
{
    return settings.getIntSetting("blue_gain");
}

void Qx3Model::setRedGain(int redGain)
{
    settings.setIntSetting("red_gain", redGain);
}
int Qx3Model::getRedGain()
{
    return settings.getIntSetting("red_gain");
}

void Qx3Model::setGreenGain(int greenGain)
{
    settings.setIntSetting("green_gain", greenGain);
}

int Qx3Model::getGreenGain()
{
    return settings.getIntSetting("green_gain");
}


void Qx3Model::setColor(uint color) {
        settings.setIntSetting("saturation", color);
//        vid_pic.colour = color;
//
//        if (ioctl (device, VIDIOCSPICT, &vid_pic) == -1) {
//                cerr << "ioctl (VIDIOCSPICT)";
//                std::ofstream to(cpia_file.c_str());
//                to << "saturation: " << color << endl;
//                to.close();
//        }
//
}

void Qx3Model::setQuality(int quality)
{
    settings.setIntSetting("target_quality", quality);
}

int Qx3Model::getQuality()
{
    return settings.getIntSetting("target_quality");
}





